using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class TestPipelineSorter : RapidHardware
    {
        PipelineStage oPipeIn;
        PipelineStage oPipe0;
        PipelineStage oPipe1;
        PipelineStage oPipe2;
        PipelineSorter oSorter;

        public override bool ConfigureSettings()
        {
            Settings.UseStart = false;
            Settings.BuildHardware = true;
            Settings.ForceBuildHardware = false;
            Settings.RunFromXilinx = true;
            Settings.ClockFrequency = 10;
            Settings.UseSDRAM = true;
            Settings.BuildRemote = false;
            return true;
        }

        public override bool GenerateStructure(TopLevelComponent TopLevelComponent)
        {
            oPipeIn = new PipelineStage(TopLevelComponent, "pipeIn", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 5);
            oPipe0 = new PipelineStage(TopLevelComponent, "pipe0", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 5);
            oPipe1 = new PipelineStage(TopLevelComponent, "pipe1", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 5);
            oPipe2 = new PipelineStage(TopLevelComponent, "pipe2", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 5);

            oSorter = new PipelineSorter(TopLevelComponent, "sorter", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 5, 3, 2);

            oSorter.InputBus.Join(oPipeIn.OutputBus);
            oPipe0.InputBus.Join(oSorter.DefineOutput("out0", 0));
            oPipe1.InputBus.Join(oSorter.DefineOutput("out1", 1));
            oPipe2.InputBus.Join(oSorter.DefineOutput("out2", 2));

            SystemInterface.AddSignalSource("stall0", oPipe0.OutputBus.Stall, 1);
            SystemInterface.AddSignalSource("stall1", oPipe1.OutputBus.Stall, 1);
            SystemInterface.AddSignalSource("stall2", oPipe2.OutputBus.Stall, 1);

            SystemInterface.AddSignalSource("data_i", oPipeIn.InputBus.Data, 0);
            SystemInterface.GetSignalSource("data_i").SignalFormat = SignalFormat.Unsigned; 
            SystemInterface.AddSignalSource("data_ready_i", oPipeIn.InputBus.DataReady, 0);

            TopLevelComponent.TestBusWrite.Join(0);

            return true;
        }

        public override bool ConfigureSignalViews(TopLevelComponent TopLevelComponent)
        {

         /*   SystemInterface.AddSignalView("pipe0_o", oPipe2.OutputBus.Data);
            SystemInterface.FormatSignalView("pipe0_o", SignalFormat.Unsigned);
            SystemInterface.AddSignalView("pipe1_o", oPipe3.OutputBus.Data);
            SystemInterface.FormatSignalView("pipe1_o", SignalFormat.Unsigned);
            SystemInterface.AddSignalView("pipe2_o", oPipe4.OutputBus.Data);
            SystemInterface.FormatSignalView("pipe2_o", SignalFormat.Unsigned);
            
            SystemInterface.AddSignalView("stall_o", oPipe1.OutputBus.Stall);
            SystemInterface.AddSignalView("data_ready0_o", oPipe2.OutputBus.DataReady);
            SystemInterface.AddSignalView("data_ready1_o", oPipe3.OutputBus.DataReady);
            SystemInterface.AddSignalView("data_ready2_o", oPipe4.OutputBus.DataReady);
            */

            SystemInterface.AddSignalView("data_ready0_i", "sorter.select_0");
            SystemInterface.AddSignalView("data_ready1_i", "sorter.select_1");
            SystemInterface.AddSignalView("data_ready2_i", "sorter.select_2");

            SystemInterface.AddSignalView("data0_o", "sorter.out0.DATA_O");
            SystemInterface.AddSignalView("data_ready0_o", "sorter.out0.DATA_READY_O");
            SystemInterface.AddSignalView("data1_o", "sorter.out1.DATA_O");
            SystemInterface.AddSignalView("data_ready1_o", "sorter.out1.DATA_READY_O");
            SystemInterface.AddSignalView("data2_o", "sorter.out2.DATA_O");
            SystemInterface.AddSignalView("data_ready2_o", "sorter.out2.DATA_READY_O");



            /*SystemInterface.AddSignalView("in_data", oPipe1.OutputBus.Data);
            SystemInterface.AddSignalView("in_data_ready", oPipe1.OutputBus.DataReady);
            SystemInterface.AddSignalView("in_stall", oPipe1.OutputBus.Stall);*/

            SystemInterface.AddSignalView("address", "sorter.address");

            return true;
        }


        private void ShowOutputs(HardwareScript poScript, int piTime)
        {
            poScript.SignalView(piTime, "address");
            poScript.SignalView(piTime, "data_ready0_i");
            poScript.SignalView(piTime, "data_ready1_i");
            poScript.SignalView(piTime, "data_ready2_i");

            poScript.SignalView(piTime, "data0_o");
            poScript.SignalView(piTime, "data_ready0_o");
            poScript.SignalView(piTime, "data1_o");
            poScript.SignalView(piTime, "data_ready1_o");
            poScript.SignalView(piTime, "data2_o");
            poScript.SignalView(piTime, "data_ready2_o");



            /*poScript.SignalView(piTime, "pipe0_o");
            poScript.SignalView(piTime, "pipe1_o");
            poScript.SignalView(piTime, "pipe2_o");*/
            
            /*poScript.SignalView(piTime, "data_ready0_o");
            poScript.SignalView(piTime, "data_ready1_o");
            poScript.SignalView(piTime, "data_ready2_o");*/
            
            /*
            poScript.SignalView(piTime, "in_data");
            poScript.SignalView(piTime, "in_data_ready");
            poScript.SignalView(piTime, "in_stall");
            */

            poScript.Echo(piTime, "----");
        }

        private void SetInputs(HardwareScript poScript, int piTime, int piData, int piDataReady, int piStall0, int piStall1, int piStall2)
        {
            poScript.SignalOut(piTime, "data_i", piData.ToString());
            poScript.SignalOut(piTime, "data_ready_i", piDataReady.ToString());

            poScript.SignalOut(piTime, "stall0", piStall0.ToString());
            poScript.SignalOut(piTime, "stall1", piStall1.ToString());
            poScript.SignalOut(piTime, "stall2", piStall2.ToString());
            poScript.Pause(piTime+1);
        }

        public override bool GenerateHardwareScripts()
        {
            HardwareScript oScript = HardwareScripts.NewScript("test");
            oScript.NoReset = false;
            SetInputs(oScript,0,0,0,0,0,0);
            ShowOutputs(oScript, 0);

            SetInputs(oScript,1,5,1,0,0,0);
            ShowOutputs(oScript, 1);
            SetInputs(oScript, 2, 5, 1, 0,0,0);
            ShowOutputs(oScript, 2);
            SetInputs(oScript, 3, 23, 1, 0,0,0);
            ShowOutputs(oScript, 3);
            SetInputs(oScript, 4, 30, 1, 0,0,0);
            ShowOutputs(oScript, 4);
            ShowOutputs(oScript, 5);
            ShowOutputs(oScript, 6);
            ShowOutputs(oScript, 7);

            return true;
        }

    }
}

